//// GMeter.cpp ///////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////

#include "GMeter.h" 

static GTimer timer; //Global animation timer

///////////////////////////////////
BEGIN_EVENT_TABLE(GMeter, wxPanel) 
	EVT_MOUSE_EVENTS (GMeter::OnMouse)
	EVT_PAINT (GMeter::OnPaint)
END_EVENT_TABLE() 

///////////////////////////////////////////////////////////////////////////////////////////////////
GMeter::GMeter(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, bool falloff)
{ 
	// SETTINGS
	SPEED1 = 2;
	SPEED2 = 100;
	PEAK = 1;
	SPACING = 5;
	
	mySize = size;

	hitFlag = false;
	eraseFlag = false;

	(void)Create(parent, id, pos, size); 

#ifdef WIN32
	//Falloff painting not ready on MAC or LINUX
	if(falloff){
		timer.AddMeter(*this);  //add meter to the timer event
	}
#endif //WIN32
} 

/////////////////
GMeter::~GMeter() 
{ 
	delete memDC;
	delete cdc2;
	
	//destroy the meter in the timer class too.
	for(int i=0; i<=timer.meters; i++){
		if(timer.m_pointers[i] == this){
			
			while(i <= timer.meters){
				timer.m_pointers[i] = timer.m_pointers[i+1];
				i++;
			}

			timer.meters--;
			break;
		}
	}
} 

////////////////////////////////////////////////////////////////////////////////////////////////////////
bool GMeter::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) 
{ 
	if(!wxPanel::Create(parent, id, pos, size, wxNO_BORDER, wxT(""))) 
		return false; 

	memDC = new wxMemoryDC();

	cdc2 = new wxClientDC(this); //MAC does not like this, we must blit in the paint event.
	SetBackgroundColour(wxColour(0,0,0));
	eraseFlag = true;
	hitFlag = false;
	Refresh();

	return true; 
} 

////////////////////////////////////////////////////
void GMeter::OnPaint(wxPaintEvent &WXUNUSED(event)) 
{ 
	wxBufferedPaintDC dc(this); 

	if(eraseFlag){
		dc.SetBackground(wxColour(0, 0, 0)); 
		dc.SetBackgroundMode(wxSOLID); 
		dc.Clear(); 
		dc.SetBrush(*wxTRANSPARENT_BRUSH); 
		eraseFlag = false;
	}
	
	if(hitFlag){
		dc.Blit(0, 0, mySize.x, mySize.y, memDC, 0, 0);
		hitFlag = false;
	}

	else{
		dc.SetBackground(wxColour(0, 0, 0)); 
		dc.SetBackgroundMode(wxSOLID); 
		dc.Clear(); 
		dc.SetBrush(*wxTRANSPARENT_BRUSH); 
	}
} 

/////////////////////////
void GMeter::Hit(int val)
{
	wxCriticalSectionLocker locker(critical); //Make this funtion thread safe.

	wxBitmap temp = wxBitmap(wxBitmap(mySize.x, mySize.y, -1));
	memDC->SelectObject(temp); 

	sw.Start();
	falloff = (val * mySize.y) / 100;

	falltemp = falloff;
	peakfall = falloff;
	value = val;

	int position = (mySize.y * value) / 100;
	int b = SPACING -1;

	for(int i=0; i<position; i++){

		int percent = ((i * 100) / mySize.y);
		int color1 = (255 * percent) / 100 * 2;
		if(percent > 50){color1 = 255;}
		int color2 = 255 - ((255 * percent) / 100 * 2);
		if(percent < 51){color2 = 255;}
		
		if(i != b || i == position-1){
			memDC->SetPen(wxColour(color1,color2,0));
			memDC->DrawLine(0, mySize.y -1 -i, mySize.x, mySize.y -1 -i);
		}	
		else{b=b+SPACING;}
		
		if(i == position-1){peakcolor = wxColour(color1, color2, 0);} //store the peak color
	}
	
	hitFlag = true;
	Refresh();
}

/////////////////////////////////////////
void GMeter::OnMouse(wxMouseEvent &event) 
{ 
	if(event.RightUp())
	{
		GetParent()->ProcessEvent(event); //Let event bleed through to the parent.
	}
}


////////////////////////////
GTimer::GTimer() : wxTimer()
{
	Start(1,false);
}

////////////////////////////////////////
void GTimer::AddMeter(GMeter &m_pointer)
{
	m_pointers[meters] = &m_pointer;
	meters++;
}

/////////////////////////////////////////
void GTimer::Notify()
{
	
	//process falloff animations
	if(meters > 0){
		for(int i=0; i<meters; i++){
			if(m_pointers[i]->falloff > 0){
				
				m_pointers[i]->temp = m_pointers[i]->sw.Time();

				if(m_pointers[i]->falltemp > 0){

					m_pointers[i]->cdc2->SetPen(wxColour(0, 0, 0));
					m_pointers[i]->cdc2->SetBrush(wxColour(0, 0, 0));

                    m_pointers[i]->cdc2->DrawRectangle(0, m_pointers[i]->mySize.y +m_pointers[i]->PEAK -m_pointers[i]->falloff, m_pointers[i]->mySize.x, m_pointers[i]->temp / m_pointers[i]->SPEED1);
					
                    m_pointers[i]->falltemp =  m_pointers[i]->falloff - (m_pointers[i]->temp  / m_pointers[i]->SPEED1);		
				}

				else if(m_pointers[i]->peakfall > -m_pointers[i]->SPEED2 && m_pointers[i]->PEAK){
					m_pointers[i]->cdc2->SetPen(wxColour(0, 0, 0));
					m_pointers[i]->cdc2->DrawLine(0, m_pointers[i]->mySize.y -m_pointers[i]->peakfall, m_pointers[i]->mySize.x, m_pointers[i]->mySize.y -m_pointers[i]->peakfall);
					m_pointers[i]->peakfall = m_pointers[i]->peakfall - (m_pointers[i]->temp / m_pointers[i]->SPEED2);
					m_pointers[i]->cdc2->SetPen(m_pointers[i]->peakcolor);
					m_pointers[i]->cdc2->DrawLine(0, m_pointers[i]->mySize.y -m_pointers[i]->peakfall, m_pointers[i]->mySize.x, m_pointers[i]->mySize.y -m_pointers[i]->peakfall);
				}

				else{
					m_pointers[i]->falloff = 0;
					m_pointers[i]->sw.Pause();
				}
			}
		}
    }
}
